package org.yn.car.service.impl;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yn.base.constants.BaseConstants;
import org.yn.base.constants.CarConstants;
import org.yn.base.service.impl.BaseServiceImpl;
import org.yn.base.util.BaiduAuditUtil;
import org.yn.base.util.VelocityUtils;
import org.yn.car.doc.CarDoc;
import org.yn.car.domain.Car;
import org.yn.car.domain.CarDetail;
import org.yn.car.domain.CarOperateLog;
import org.yn.car.domain.CarType;
import org.yn.car.mapper.CarDetailMapper;
import org.yn.car.mapper.CarMapper;
import org.yn.car.mapper.CarOperateLogMapper;
import org.yn.car.repository.CarDocRepository;
import org.yn.car.service.ICarService;
import org.yn.dept.domain.Shop;
import org.yn.emp.domain.Employee;
import org.yn.exception.AssertUtil;
import org.yn.exception.ResponseCode;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yn
 * @since 2023-08-21
 */
@Service
public class CarServiceImpl extends BaseServiceImpl<Car> implements ICarService {


    @Autowired
    CarMapper carMapper;
    @Autowired
    CarDetailMapper carDetailMapper;
    @Autowired
    CarOperateLogMapper carOperateLogMapper;
    @Autowired
    private CarOperateLogMapper logMapper;
    @Autowired
    private CarDocRepository carDocRepository;
    
    @Value("${carDetail.templateFilePathAndName}")
    private String templatePath;

    @Value("${carDetail.targetFilePathAndName}")
    private String targetPath;

    @Transactional
    @Override
    public void insert(Car car, Employee loginAdmin) {
        //创建时间，
        car.setCreatetime(new Date());
        //店铺信息
        car.setShopId(loginAdmin.getShop().getId());
        car.setShopname(loginAdmin.getShop().getName());

        //状态
        car.setState(BaseConstants.CAR_STATE_OFFLINE);

        //销售人员
        car.setSellerId(loginAdmin.getId());


        //审核  (标题,封面,基本信息）
        List<String> texts = Arrays.asList(car.getTitle(), car.getCarDetail().getInfo());
        List<String> imgs = Arrays.asList(car.getCover());
        Map<String, Object> censor = BaiduAuditUtil.censor(texts, imgs);
        Boolean flag = (Boolean)censor.get("success");
        if (flag){
            car.setAuditstate(CarConstants.CAR_AUDIT_STATE_SUCCESS);
        }else {
            car.setAuditstate(CarConstants.CAR_AUDIT_STATE_FAIL);
        }
        //新增car
        super.insert(car);

        // 基本信息detail
        CarDetail carDetail = new CarDetail();
        carDetail.setCarId(car.getId());
        carDetail.setCartitle(car.getTitle());
        carDetail.setInfo(car.getCarDetail().getInfo());
        carDetailMapper.insert(carDetail);


        // 添加审核日志
        CarOperateLog log = new CarOperateLog();
        log.setCarId(car.getId());
        if(flag){
            log.setOperateType(CarConstants.CAR_OPERATE_TYPE_AUDIT_SUCCESS);
            log.setNote("系统审核通过!");
        }else{
            log.setOperateType(CarConstants.CAR_OPERATE_TYPE_AUDIT_FAIL);
            log.setNote(censor.get("message").toString());
        }
        log.setOperateId(0L);       // 自动审核的操作人不应该是当前登录人,而是null或者0,表示是系统审核
        log.setOperateTime(new Date());
        carOperateLogMapper.insert(log);


    }

    /**
     *
     * @param ids
     * @param loginUser
     * @return  String  因为要给前端显示几条成功几条失败
     */
    @Transactional
    @Override
    public String onsale(List<Long> ids, Employee loginUser) {

        // 参数校验--非空校验  前端不可靠
        AssertUtil.isNotNull(ids, ResponseCode.RESPONSE_CODE_40013);//断言处理 如果空则报错没有选中数据

        // 审核状态的校验
        // 如果选择的数据中有几条没有审核通过 则返回 ：通过了X条 ，不通过的X条，
        //如果全部不通过则返回 40014

        //先根据ids批量查询 出List<car>
        List<Car> list= carMapper.batchSelectByCarId(ids);

        //找出符合条件的 下架状态的+审核成功的
        list = list.stream().filter(x -> x.getState() == CarConstants.CAR_STATE_OFFLINE
                && x.getAuditstate() == CarConstants.CAR_AUDIT_STATE_SUCCESS).collect(Collectors.toList());

        //判断是否为空 ,就是没有满足条件的
        AssertUtil.isNotNull(list,ResponseCode.RESPONSE_CODE_40015);//断言  抛出40015 没有一个符合条件的


        // 修改当前满足条件的车辆数据的数据库的状态=上架,并添加上架时间
        List<Long> idList = list.stream().map(Car::getId).collect(Collectors.toList()); //获取id
        carMapper.onsale(idList,CarConstants.CAR_STATE_ONLINE);//状态设置为上线

        // 添加上架日志 当前上架的有几条数据,就要新增几条日志
        saveLog(loginUser, idList,CarConstants.CAR_OPERATE_TYPE_ONLINE);

        // 将数据添加到es中
        // 有数据库和其他中间件操作时,先操作数据库,因为出现错误,中间件不能回滚,mysql可以

        List<CarDoc> docs = getCarDocsByCar(list);
        carDocRepository.saveAll(docs);  //保存数据

        String msg = "当前传入一共%s条数据,成功%s条,失败%s条！";
        msg = String.format(msg,ids.size(),idList.size(),(ids.size() - idList.size()));


        // 给上架的每个商铺生成静态界面
        for (CarDoc doc : docs) {
            String path  = this.targetPath+"\\"+doc.getId()+".html";
            VelocityUtils.staticByTemplate(doc,this.templatePath,path);
            System.out.printf("-----生成模板成功------"+doc.getId());
        }

        return msg;
    }

    @Override
    public void offsale(List<Long> ids, Employee loginUser) {
        // 参数非空校验
        // 下架没有必要做状态校验,因为本身是下架的话不影响结果
        AssertUtil.isNotNull(ids,ResponseCode.RESPONSE_CODE_40014);

        // 修改数据库的状态=下架,并添加下架时间
        carMapper.offsale(ids,CarConstants.CAR_STATE_OFFLINE);

        // 添加下架的日志
        saveLog(loginUser,ids,CarConstants.CAR_OPERATE_TYPE_OFFLINE);

        //  从es中删除要下架的车辆信息
        for (Long id : ids) { //循环来处理
            carDocRepository.deleteById(id);
        }


        //  下架时删除静态页面
        for (Long id : ids) {
            String path  = this.targetPath+"\\"+id+".html";
            File file = new File(path);
            if(file.exists()){
                file.delete();
            }
        }
    }

    /**
     * doc
     * @param list
     * @return
     */
    private List<CarDoc> getCarDocsByCar(List<Car> list) {
        List<CarDoc> docs = new ArrayList<>();
        for (Car car : list) {
            CarDoc doc = new CarDoc();
            BeanUtils.copyProperties(car,doc);
            // 处理车辆的店铺
            Shop shop = car.getShop();
            if(Objects.nonNull(shop)){
                doc.setShopName(shop.getName());
                doc.setShopAddress(shop.getAddress());
                GeoPoint geoPoint = new GeoPoint(shop.getLat(), shop.getLon());
                doc.setShopPoint(geoPoint);
            }

            // 处理车辆的类型
            CarType carType = car.getCarType();
            if(Objects.nonNull(carType)){
                doc.setTypeName(carType.getName());
            }

            // 处理详情信息
            CarDetail carDetail = car.getCarDetail();
            if(Objects.nonNull(carDetail)){
                doc.setCarInfo(carDetail.getInfo());
            }
            docs.add(doc);
        }
        return docs;
    }

    //批量保存log日志的方法

    /**
     *
     * @param loginUser
     * @param idList   是符合条件的CarId
     * @param operateType
     */
    private void saveLog(Employee loginUser, List<Long> idList,Integer operateType) {
        String state = operateType == CarConstants.CAR_OPERATE_TYPE_ONLINE ? "上架":"下架";
        String note = "%s"+state+"了id=%s的车辆";
        List<CarOperateLog> logs = new ArrayList<>();
        for (Long id : idList) {
            CarOperateLog log = new CarOperateLog();
            log.setCarId(id);
            log.setOperateType(operateType);
            log.setOperateTime(new Date());
            log.setOperateId(loginUser.getId()); // 取当前登录人的id
            log.setNote(String.format(note, loginUser.getRealName(),id));
            logs.add(log);
        }
        logMapper.batchInsert(logs);
    }
}
